// Parser.cpp	-	Parser class
// Parses two text files and creates a data structure of Nodes.
// The Nodes are stored in a unordered_map<string, Node*>.

#include <iostream>
#include <fstream>
#include <sstream>
#include <QFile>
#include <QTextStream>
#include <QStringList>
#include <QPair>
#include "Parser.h"

// Allocates memory for an unordered_map<string, Node*> (typedef'd as NodeMap)
// Calls the two parser functions and passes the map by reference, then
// returns the address of the NodeMap.
NodeMap* Parser::parseData(QString locsFilename, QString connsFilename)
{
    NodeMap *nodeListPtr = new NodeMap;
    parseLocations(locsFilename, nodeListPtr);
    parseConnections(connsFilename, nodeListPtr);
    return nodeListPtr;
}

// Parses a text file holding node names and X,Y coordinates.
// This function will return a QList of the node names, used
// for populating a dropdown list for selecting available nodes.
QList<QString> Parser::parseNodeNames(QString locsFilename)
{
    QFile inFile(locsFilename);
    QList<QString> nodeNames;
    QString name;
    if (inFile.open(QIODevice::ReadOnly))
    {
        QTextStream inStream(&inFile);
        QString buffer;
        while (!inStream.atEnd())
        {
            buffer = inStream.readLine();
            name = buffer.split(" ")[0];
            if (name == "END")
                break;
            else
                nodeNames.push_back(name);
        }
        inFile.close();
    }
    else
        exit(1);
    qSort(nodeNames);
    return nodeNames;
}

// Parses a text file holding node names and X,Y coordinates.
// The text file must have this format:
// A1 30 48
// A2 30 178
// A3 30 483
// END
void Parser::parseLocations(QString filename, NodeMap *nodeMapPtr)
{
    QFile inFile(filename);
    QString name;
	int x;
	int y;
    if (inFile.open(QIODevice::ReadOnly))
    {
        QTextStream inStream(&inFile);
        QString buffer;
        while (!inStream.atEnd())
        {
            buffer = inStream.readLine();
            QStringList bufferList = buffer.split(" ");
            name = bufferList.at(0);
			if (name == "END")	//Reached end of locations file
                break;
            x = bufferList.at(1).toInt();
            y = bufferList.at(2).toInt();
            
            nodeMapPtr->insert(name, (new Node(name, x, y)));
        }
        inFile.close();
    }
    else
        exit(1);
}

// Parses a text file holding the node name, number of connections, and
// the names of each connection. The text file must have this format:
// A1 2 B1 A2
// A2 3 A1 B2 A4
// A3 3 A2 B5 A5
// END
void Parser::parseConnections(QString filename, NodeMap *nodeMapPtr)
{
    QFile inFile(filename);
    //std::ifstream inFile(filename.c_str(), std::ios::in);
    //std::string buffer1;
    //std::string buffer2;
    QList<QString> pieces;
    if (inFile.open(QIODevice::ReadOnly))
    {
        QTextStream inStream(&inFile);
        QString lineFromFile;
        QString buffer;
        while (!inStream.atEnd())
        {
            pieces.clear();
            lineFromFile = inStream.readLine();
            QTextStream streamFromLine(&lineFromFile, QIODevice::ReadOnly);
            while (!streamFromLine.atEnd())
            {
                streamFromLine >> buffer;
                pieces.push_back(buffer);
            }

            if (pieces.at(0) == "END")	//Reached end of connections file
                break;

            //Add the new connections to the Node pointed to by this iterator
            NodeMap::iterator itrForNode = nodeMapPtr->find(pieces.at(0));
            for (size_t j = 2; j < pieces.size(); ++j)
            {
                //This iterator points to the Nodes we want to add as new connections
                NodeMap::iterator itrForNewConnection = nodeMapPtr->find(pieces.at(j));

                if (itrForNewConnection == nodeMapPtr->end())
                    qDebug() << "Node " << pieces.at(j) << " not found in NodeMap by parseConnections().";

                itrForNode.value()->addConnection(itrForNewConnection.value());
            }
        }
        inFile.close();
    }
    else
        exit(1);
}
